﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;


namespace TopShelfServiceBatchInstaller
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private readonly string _childDir;
        private double _currentProgressPercent;
        private const string AppInstallDir = "c:\\Program Files\\TopShelfServices";

        public static readonly DependencyProperty InstallerItemsProperty = DependencyProperty.Register(
            "InstallerItems", typeof(List<TopShelfInstallerItem>), typeof(MainWindow), new PropertyMetadata(default(List<TopShelfInstallerItem>)));

        public List<TopShelfInstallerItem> InstallerItems
        {
            get { return (List<TopShelfInstallerItem>)GetValue(InstallerItemsProperty); }
            set { SetValue(InstallerItemsProperty, value); }
        }

        public MainWindow()
        {
            InitializeComponent();

            _childDir = Path.Combine(Directory.GetCurrentDirectory(), "Services");
            Directory.CreateDirectory(AppInstallDir);
            Directory.CreateDirectory(_childDir);

            // Add version info to title
            var isRunningAsAdmin = Helper.IsAdministrator();
            RootGrid.IsEnabled = isRunningAsAdmin;

            Title = isRunningAsAdmin? $"TopShelf服务安装工具 V{GetType().Assembly.GetName().Version}" : "请用管理员权限重启应用";

            RefreshInstallers();
        }

        private void RefreshInstallers()
        {
            InstallerItems = EnumerateChildDirForInstallers();
        }


        private List<TopShelfInstallerItem> EnumerateChildDirForInstallers()
        {
            var output = new List<TopShelfInstallerItem>();
            var subDirs = Directory.EnumerateDirectories(_childDir).ToArray();
            if (subDirs.Any())
            {
                foreach (var dir in subDirs)
                {
                    var installerItem = new TopShelfInstallerItem();

                    var files = Directory.GetFiles(dir);
                    var isTopShelfInstallerDir = files.Any(f => Path.GetFileName(f) == "Topshelf.dll");
                    if (!isTopShelfInstallerDir) continue;

                    var exeFiles = files.Where(f => f.EndsWith(".exe")).ToArray();
                    var exeCount = exeFiles.Length;
                    if (exeCount != 1)
                    {
                        Log($"找到{exeCount}个exe文件在{dir}, 请确保该文件夹有唯一的exe文件", LogLevel.Warn);
                        continue;
                    }

                    var path = exeFiles[0];
                    installerItem.SourceDir = dir;
                    installerItem.Name = Path.GetFileNameWithoutExtension(path);
                    installerItem.Version = FileVersionInfo.GetVersionInfo(path).FileVersion;


                    // Check install status
                    // Check if already install
                    var installServicesDirs = Directory.EnumerateDirectories(AppInstallDir).ToArray();
                    var oldInstallDirs = installServicesDirs.Where(d => Path.GetFileName(d) == installerItem.Name).ToArray();
                    var hasInstalled = oldInstallDirs.Length == 1;
                    if (hasInstalled)
                    {
                        var oldExeFile = Directory.GetFiles(oldInstallDirs[0]).Single(f => f.EndsWith(".exe"));
                        installerItem.PreviousVersion = FileVersionInfo.GetVersionInfo(oldExeFile).FileVersion;
                        var currentVersion = new Version(installerItem.Version);
                        var previousVersion = new Version(installerItem.PreviousVersion);
                        installerItem.InstallStatus = currentVersion > previousVersion ? InstallStatus.Upgrade :
                            currentVersion == previousVersion ? InstallStatus.AlreadyInstall : InstallStatus.DownGrade;

                        // Set default ShouldInstall option
                        if (installerItem.InstallStatus == InstallStatus.FirstInstall || installerItem.InstallStatus == InstallStatus.Upgrade)
                        {
                            installerItem.ShouldInstall = true;
                        }
                        else
                        {
                            installerItem.ShouldInstall = false;
                        }
                    }

                    output.Add(installerItem);
                }


                return output;
            }

            return output;
        }

        private void Log(string message, LogLevel logLevel)
        {
            var foreground = logLevel == LogLevel.Info ? Brushes.Black :
                logLevel == LogLevel.Debug ? Brushes.DarkSlateGray :
                logLevel == LogLevel.Warn ? Brushes.Gold : Brushes.Red;
            LogTextBox.Document.Blocks.Add(new Paragraph(new Run(message) { Foreground = foreground }));
        }

        private async void OnInstallButtonClick(object sender, RoutedEventArgs e)
        {
            if (InstallerItems == null || !InstallerItems.Any()) return;

            var itemsToInstall = InstallerItems.Where(i => i.ShouldInstall).ToArray();
            if (!itemsToInstall.Any()) return;

            var stopwatch = Stopwatch.StartNew();
            var totalPendingInstall = itemsToInstall.Length;
            var progressIncrement = 100 / totalPendingInstall;
            CurrentProgressPercent = 0d;

            for (var index = 0; index < totalPendingInstall; index++)
            {
                var item = itemsToInstall[index];
                var needToUninstall = item.InstallStatus != InstallStatus.FirstInstall;
                var currentProgressIncrement = needToUninstall ? progressIncrement / 2 : progressIncrement;
                // Display current install item
                if (needToUninstall)
                {
                    ReportCurrentTask($"正在卸载{item.Name} V{item.PreviousVersion}...");
                    var debugMessage = await item.UninstallPreviousAsync(AppInstallDir);
                    Log(debugMessage, LogLevel.Debug);
                    CurrentProgressPercent += currentProgressIncrement;
                }

                ReportCurrentTask($"正在安装{item.Name} V{item.Version}");
                var message = await item.InstallAsync(AppInstallDir);
                Log(message, LogLevel.Debug);

                //Display percent
                CurrentProgressPercent =
                    index == totalPendingInstall - 1 ? 100 : CurrentProgressPercent + currentProgressIncrement;
            }
            ReportCurrentTask($"安装完毕, 耗时{stopwatch.ElapsedMilliseconds}ms");

            RefreshInstallers();
        }

        public double CurrentProgressPercent
        {
            get => _currentProgressPercent;
            set
            {
                _currentProgressPercent = value;
                InstallProgressBar.Value = value;

            }
        }

        private void ReportCurrentTask(string message)
        {
            ProgressTaskTextBlock.Text = $"{message} [{CurrentProgressPercent}%]";
            Log(message, LogLevel.Info);
        }

        private async void OnUninstallMenuItemClicked(object sender, RoutedEventArgs e)
        {
            var menuItem = (MenuItem)sender;
            var installerItem = (TopShelfInstallerItem)menuItem.DataContext;
            Log($"正在卸载{installerItem.Name}(V{installerItem.PreviousVersion})", LogLevel.Info);
            var debugMessage = await installerItem.UninstallPreviousAsync(AppInstallDir);
            Log(debugMessage, LogLevel.Debug);
            Log($"卸载完毕", LogLevel.Info);
            RefreshInstallers();
        }
    }



    public enum LogLevel
    {
        Debug,
        Info,
        Warn,
        Fatal
    }
}
